package com.remoter.monitor.web.util;

import java.lang.reflect.Constructor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.remoter.basic.configure.IConfiguration;
import com.remoter.basic.configure.support.AbstractConfiguration;
import com.remoter.basic.util.Final;
import com.remoter.basic.util.StringUtil;
import com.remoter.core.BootStrap;

import io.undertow.Handlers;
import io.undertow.Undertow;
import io.undertow.Undertow.Builder;
import io.undertow.server.handlers.PathHandler;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager;

/**
 * @author			koko
 * @date 			2017-08-10 17:48:53
 * @description 	类功能说明
 */
public class Application extends BootStrap{
	
	protected static volatile boolean RUNNING = false;
	protected static final Logger logger = LoggerFactory.getLogger(Application.class);
	protected static IConfiguration configuration;
	public static void main(String[] args) {
		try{
			initConfiguration(args);
			configuration = AbstractConfiguration.getConfiguration();
			Application.run(Application.class);
		}catch(Exception e){
			logger.error(e.getMessage(),e);
			System.exit(1);
		}
	}
	
	private static void run(Class<?> type)throws Exception{
		String bootstrapClassString = configuration.getOption(FinalMonitorWeb.O_MONITOR_BOOTSTRAP);
		if(StringUtil.isBlank(bootstrapClassString)){
			logger.warn("monitor.bootstrap class not found");
			return;
		}
		Class<?> clazz = Class.forName(bootstrapClassString);
		Constructor<?> constructor = clazz.getConstructor(Class.class);
		Object instanceObject = constructor.newInstance(type);
		if(!(instanceObject instanceof Application)){
			throw new IllegalArgumentException(bootstrapClassString + " must extend Application ");
		}
		final Application application = (Application)instanceObject;
		Runtime.getRuntime().addShutdownHook(new Thread(){
			@Override
			public void run(){
				try{
					application.close();
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		});
		application.start();
	}
	
	protected final String host;
	protected final int port;
	protected final String context;
	protected final String name;
	
	protected final DeploymentInfo deploymentInfo;
	protected final DeploymentManager deploymentManager;
	protected Undertow undertow;
	
	public Application(Class<?> type){
		this.host = configuration.getOption(FinalMonitorWeb.O_MONITOR_HOST);
		this.port = configuration.getOption(FinalMonitorWeb.O_MONITOR_PORT);
		this.context = configuration.getOption(FinalMonitorWeb.O_MONITOR_CONTEXT);
		this.name = configuration.getOption(Final.O_VAL_SERVER);
		this.deploymentInfo = Servlets.deployment();
		this.deploymentInfo.setClassLoader(type.getClassLoader());
		this.deploymentInfo.setDeploymentName(this.name);
		this.deploymentInfo.setContextPath(this.context);
		this.deploymentInfo.addWelcomePage(configuration.getOption(FinalMonitorWeb.O_MONITOR_WELCOME));
		this.initDeploymentInfo();
		this.deploymentManager = Servlets.defaultContainer().addDeployment(this.deploymentInfo);
		this.initDeploymentManager();
	}
	
	public synchronized void start()throws Exception{
		if(RUNNING){
			throw new IllegalStateException("server is running ");
		}
		logger.info(String.format("server start [%s:%s]",this.host,this.port));
		RUNNING = true;
		this.deploymentManager.deploy();
		PathHandler pathHandler = Handlers.path(Handlers.redirect(this.context));
		pathHandler.addPrefixPath(this.context,this.deploymentManager.start());
		Builder builder = Undertow.builder();
		builder.addHttpListener(this.port,this.host);
		builder.setHandler(pathHandler);
		this.undertow = builder.build();
		this.undertow.start();
	}
	public synchronized void close()throws Exception{
		if(!RUNNING){
			throw new IllegalStateException("server is stop ");
		}
		logger.info(String.format("server stop [%s:%s]",this.host,this.port));
		RUNNING = false;
		if(null != this.deploymentManager){
			this.deploymentManager.stop();
		}
		if(null != this.undertow){
			this.undertow.stop();
		}
	}
	
	public void initDeploymentInfo(){}
	public void initDeploymentManager(){}
	
}